import IndexDBWrapper from 'indexdbwrapper'
import {FileLoader, EventDispatcher} from 'three'

const fileLoader = new FileLoader()
fileLoader.setResponseType('blob')

class IndexDBApi extends EventDispatcher {
  constructor(dbName, version, storeName, updateTime) {
    super()
    this.dbName = dbName
    this.version = version
    this.storeName = storeName
    this.updateTime = updateTime
    this.runingClear = false

    const db = this.db = new IndexDBWrapper(dbName, version, {
      onupgradeneeded(event) {
        const db = event.target.result // 数据库对象
        if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName, {keyPath: 'id'}) // 创建表主键为id
      }
    })
    db.open()
  }

  async getById(id) {
    return await this.db.get(this.storeName, id)
  }

  async updateById(data) {
    return await this.db.put(this.storeName, data)
  }

  async add(data) {
    return await this.db.add(this.storeName, data)
  }

  async delete(id) {
    return await this.db.delete(this.storeName, id)
  }

  async clear() {
    return this.db.clear(this.storeName)
  }

  async getFileUrlAsync(_url, onProgress) {
    const data = await this.db.get(this.storeName, _url)
    let url

    if (data) {
      if (data.updateTime > this.updateTime) {
        if (data.file) {
          if (onProgress) {
            onProgress(new ProgressEvent('progress', {lengthComputable: false, loaded: 0, total: 1}))
          }
          url = window.URL.createObjectURL(data.file)
          onProgress(new ProgressEvent('progress', {lengthComputable: false, loaded: 1, total: 1}))

        }

      } else {

        await this.db.delete(this.storeName, _url)
        const blob = await fileLoader.loadAsync(_url, onProgress)
        await this.add({id: _url, file: blob, updateTime: new Date().getTime()})
        url = window.URL.createObjectURL(data.file)

      }

    } else {

      const blob = await fileLoader.loadAsync(_url, onProgress)
      await this.add({id: _url, file: blob, updateTime: new Date().getTime()})
      url = window.URL.createObjectURL(blob)

    }
    return new Promise((resolve, reject) => {
      resolve(url)
    })
  }

  async getFileUrlListAsync(_urls, onProgress) {

    const size = _urls.length
    const urlList = []

    const dataTime = await this.getById(_urls[0])
    if (dataTime && this.updateTime > dataTime.updateTime) {
      await this.clear()

      for (let i = 0; i < _urls.length; i++) {

        const blob = await fileLoader.loadAsync(_urls[i], (process) => {
          process.size = size
          process.num = i + 1
          if (onProgress) onProgress(process)
        })
        await this.add({id: _urls[i], file: blob, updateTime: new Date().getTime()})
        urlList.push(window.URL.createObjectURL(blob))

      }

    } else {

      for (let i = 0; i < _urls.length; i++) {

        const url = await this.getFileUrlAsync(_urls[i], (process) => {
          process.size = size
          process.num = i + 1
          if (onProgress) onProgress(process)
        })
        urlList.push(url)

      }

    }

    return new Promise((resolve, reject) => resolve(urlList))

  }

  async getFileUrl(_url, onLoadUrl, onProgress, onError) {
    const data = await this.db.get(this.storeName, _url)

    if (data) {

      if (data.updateTime > this.updateTime) {

        if (onLoadUrl) onLoadUrl(window.URL.createObjectURL(data.file))

      } else {

        await this.db.delete(this.storeName, _url)

        fileLoader.load(_url, (blob) => {
          this.add({id: _url, file: blob, updateTime: new Date().getTime()})
          if (onLoadUrl) onLoadUrl(window.URL.createObjectURL(blob))
        }, onProgress, onError)
      }

    } else {

      fileLoader.load(_url, (blob) => {
        this.add({id: _url, file: blob, updateTime: new Date().getTime()})
        if (onLoadUrl) onLoadUrl(window.URL.createObjectURL(blob))
      }, onProgress, onError)

    }

  }

}

export default IndexDBApi
